﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;

namespace wget
{
    class Program
    {
        static void Main(string[] args)
        {
            wget w = new wget(args);
            
            //Console.ReadLine();
        }
    }

    public class wget
    {
        public string logFile;
        public bool logFileAppend = false;
        public bool logEnabled = true;
        public List<String> urls = new List<string>();
        public string baseUrl = "";
        public int retryCount = 20;
        public bool useAuth = false;
        public String username = "";
        public String password = "";

        public wget(String[] args)
        {
            OptionSet p = new OptionSet();
            p.Add("V|version", version);
            p.Add("h|help", help);
            p.Add("o|output-file=", setlogger);
            p.Add("a|append-output=", setloggerAppender);
            p.Add("q|quiet", disableLog);
            p.Add("i|input-file=", readFromFile);
            p.Add("B|base=",setBaseUrl);
            p.Add("t|tries=", setTries);
            p.Add("user=", setUsername);
            p.Add("password=", setPassword);

            List<String> extra = p.Parse(args);
            urls.AddRange(extra.ToArray());

            foreach (String url in urls)
            {
                downloadFile(url);
            }
        }

        public void downloadFile(String url)
        {
            Console.WriteLine(DateTime.Now.ToString("--yyyy-MM-dd HH:mm:ss-- ") + url);
            Uri u = new Uri(url);
            if (!u.IsAbsoluteUri)
            {
                u = new Uri(Path.Combine(baseUrl + url));
            }

            String filename = Path.GetFileName(u.LocalPath);
            Console.WriteLine("Saving to: `"+filename+"`");
            WebClient client = new WebClient();
            createProgress();

            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            client.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(client_DownloadFileCompleted);
            client.DownloadFileAsync(u, filename);
            currentFilename = filename;
        }
        public String currentFilename = "";
        void client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            Console.WriteLine();
            Console.WriteLine(DateTime.Now.ToString("--yyyy-MM-dd HH:mm:ss--") + " `"+currentFilename+"` saved");
            Console.WriteLine();
        }

        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            updateProgress(e.ProgressPercentage, e.BytesReceived.ToString());
        }

        public void createProgress()
        {
            if (logEnabled)
            {
                Console.WriteLine();
                Console.Write("  0%[                                                                 ] n/a    ");
            }
        }
        bool drawlock = false;
        public void updateProgress(int value,String speed)
        {
            if (logEnabled)
            {
                if (!drawlock)
                {
                    drawlock = true;
                    Console.SetCursorPosition(0, Console.CursorTop);
                    String percent = value.ToString().PadLeft(3, ' ') + "%";
                    String bar = "";
                    double factor = (double)value / 100;
                    int fill = (int)(factor * 54f) - 1;
                    if (fill < 0)
                    {
                        fill = 0;
                    }
                    bar = new string('=', fill);
                    bar += ">";
                    bar = bar.PadRight(54, ' ');
                    String extrainfo = speed + " bytes";

                    extrainfo = extrainfo.PadRight(18, ' ');
                    Console.Write(percent + "[" + bar + "] " + extrainfo);
                    drawlock = false;
                }
            }
        }

        #region commandline parsing
        public void setUsername(String val)
        {
            username = val;
            useAuth = true;
        }

        public void setPassword(String val)
        {
            password = val;
            useAuth = true;
        }

        public void setTries(String val)
        {
            if (val.Trim() == "inf")
            {
                val = "0";
            }
            if (!Int32.TryParse(val, out retryCount))
            {
                Console.WriteLine("Invalid value for argument -t");
            }
        }

        public void setBaseUrl(String val)
        {
            baseUrl = val;
        }

        public void readFromFile(String val)
        {
            if (val.Trim() == "-")
            {
                //Read urls from Console.readLine
                //not implemented becouse i'm lazy
            }
            else
            {
                String[] fileurls = File.ReadAllLines(val);
                this.urls.AddRange(fileurls);
            }
        }

        public void disableLog(String val)
        {
            logEnabled = false;
        }
        public void setlogger(String val)
        {
            logFile = val;
        }
        public void setloggerAppender(String val)
        {
            logFileAppend = true;
            logFile = val;
        }

        public void help(String val)
        {
            //p.Add("V|version", version);
            //p.Add("h|help", help);
            //p.Add("o|output-file=", setlogger);
            //p.Add("a|append-output=", setloggerAppender);
            //p.Add("q|quiet", disableLog);
            //p.Add("i|input-file=", readFromFile);
            //p.Add("B|base=", setBaseUrl);
            //p.Add("t|tries=", setTries);
            //p.Add("user=", setUsername);
            //p.Add("password=", setPassword);
            Console.WriteLine("Usage:");
            Console.WriteLine("wget [OPTIONS] [URL1] [URL2] ... [URLn]");
            Console.WriteLine();

            Console.WriteLine("-V, --version             Display the version of Wget");
            Console.WriteLine("-h, --help                Display this help");
            Console.WriteLine("-o, --output-file=FILE    log messages to FILE");
            Console.WriteLine("-a, --append-output=FILE  append log messages to FILE");
            Console.WriteLine("-q, --quiet               quiet (no output)");
            Console.WriteLine("-i, --input-file=FILE     download urls found in FILE");
            Console.WriteLine("-B, --base=URL            used to resolve relative urls");
            Console.WriteLine("-t, --tries=NUMBER        set number of retries to NUMBER (0 unlimits)");
            Console.WriteLine("    --user=USER           set HTTP username to USER");
            Console.WriteLine("    --password=PASS       set HTTP password to PASS");
        }

        public void version(String val)
        {
            Console.WriteLine("wget for linuxToolchain 1.0");
        }

        #endregion
    }
}
